// ======================================================================
// Copyright (C) 2013 Hell-Prototypes. / www.hellprototypes.com
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or (at
// your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
// ======================================================================
`timescale 10ns/1ns
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date:    16:29:29 06/09/2012 
// Design Name: 
// Module Name:    Core 
// Project Name: 
// Target Devices: 
// Tool versions: 
// Description: 
//
// Dependencies: 
//
// Revision: 
// Revision 0.01 - File Created
// Additional Comments: 
//
//////////////////////////////////////////////////////////////////////////////////

module Core(
		input  	CLK_Core,
		input  	nRST,
		
		input   [27:0] cmd_param,
		
		output reg [7:0] FIFO_DIN,
		output reg       FIFO_WR_EN,
		input            FIFO_FULL,
	
		input   LS_RD_Status,
		input	LS_Set_PWM,
		input   LS_Set_StepMoto,
		input   LS_Set_Pump,

		output [7:0] Logic_Out,
		input  [3:0] Logic_In
	);

parameter
	PWM_PERIOD_TOP = 20'hF423F;

reg [1:0] pwm_ch, next_pwm_ch;
reg [19:0] pwm_period_counter, next_pwm_period_counter;
reg [19:0] pwm_duty_cycle_0, next_pwm_duty_cycle_0;
reg [19:0] pwm_duty_cycle_1, next_pwm_duty_cycle_1;

reg launch_step_0, next_launch_step_0;
reg launch_step_1, next_launch_step_1;
reg enable_ctrl, next_enable_ctrl;

reg [23:0]step_ctrl_top, next_step_ctrl_top;
reg [23:0]step_ctrl_counter, next_step_ctrl_counter;
reg pump_ctrl, next_pump_ctrl;

reg [7:0] next_FIFO_DIN;
reg       next_FIFO_WR_EN;

wire [7:0] work_status;
wire EN_0, DIR_0, STEP_0;
wire EN_1, DIR_1, STEP_1;
wire edge_x_left;
wire edge_x_right;
wire edge_y_front;
wire edge_y_back;

assign Logic_Out[1:0] = pwm_ch[1:0];
assign Logic_Out[2] = pump_ctrl;
assign Logic_Out[3] = EN_1 | EN_0 | enable_ctrl;
assign Logic_Out[4] = DIR_1;
assign Logic_Out[5] = DIR_0;
assign Logic_Out[6] = ~STEP_1;
assign Logic_Out[7] = ~STEP_0;

assign edge_x_left  = Logic_In[0];
assign edge_x_right = Logic_In[1];
assign edge_y_front = Logic_In[2];
assign edge_y_back  = Logic_In[3];

assign work_status[0] = Logic_Out[3];
assign work_status[1] = DIR_0;
assign work_status[2] = DIR_1;
assign work_status[3] = pump_ctrl;
assign work_status[4] = edge_x_left;
assign work_status[5] = edge_x_right;
assign work_status[6] = edge_y_front;
assign work_status[7] = edge_y_back;

assign step_ctrl = step_ctrl_counter == step_ctrl_top;
//=============================================================================
always @(posedge CLK_Core or negedge nRST) begin
	if(!nRST) begin
		pwm_ch <= 2'b11;
		pwm_period_counter <= 0;
		pwm_duty_cycle_0 <= 0;
		pwm_duty_cycle_1 <= 0;
		
		launch_step_0 <= 0;
		launch_step_1 <= 0;
		enable_ctrl <= 0;
		step_ctrl_top <= 24'hffffff;
		step_ctrl_counter <= 0;
		pump_ctrl <= 0;
		
		FIFO_DIN <= 0;
		FIFO_WR_EN <= 0;
	end else begin
		pwm_ch <= next_pwm_ch;
		pwm_period_counter <= next_pwm_period_counter;
		pwm_duty_cycle_0  <= next_pwm_duty_cycle_0;
		pwm_duty_cycle_1  <= next_pwm_duty_cycle_1;
		
		launch_step_0 <= next_launch_step_0;
		launch_step_1 <= next_launch_step_1;
		enable_ctrl <= next_enable_ctrl;
		step_ctrl_top <= next_step_ctrl_top;
		step_ctrl_counter <= next_step_ctrl_counter;
		pump_ctrl <= next_pump_ctrl;
		
		FIFO_DIN  <= next_FIFO_DIN;
		FIFO_WR_EN <= next_FIFO_WR_EN;
	end
end

always @* begin
	/* Step Moto Control*/
	next_launch_step_0 = 0;
	next_launch_step_1 = 0;
	next_enable_ctrl = 0;
	next_step_ctrl_top = step_ctrl_top;
	next_step_ctrl_counter = step_ctrl_counter + 1;

	if(step_ctrl) begin
		next_step_ctrl_counter = 0;
	end
	/*
	stepmotor cmd:
	if cmd[27] == 1 do:
		cmd[0] : 1: ??? 0, 0: ???
	else do:
		cmd[26]: 1 = speed control,  0: set duty
		speed control: cmd[23:0] scaling 24bits
		set duty: cmd[25]: 0: run stepmotor 0,  1: run stepmotor 1
				  cmd[24]: 0/1: direction control
		          cmd[12:0]: step number
	*/
	if(LS_Set_StepMoto) begin
		if(cmd_param[27]) begin
			next_enable_ctrl = cmd_param[0];
		end else if(cmd_param[26]) begin
			next_step_ctrl_top = cmd_param[23:0];
			next_step_ctrl_counter = 0;
		end else begin
			if(cmd_param[25]) begin
				next_launch_step_1 = 1;
			end else begin
				next_launch_step_0 = 1;
			end
		end
	end

	/* PWM Control*/
	next_pwm_ch = pwm_ch;
	next_pwm_period_counter = pwm_period_counter + 1;
	next_pwm_duty_cycle_0  = pwm_duty_cycle_0;
	next_pwm_duty_cycle_1  = pwm_duty_cycle_1;
	
	if(pwm_period_counter == PWM_PERIOD_TOP) begin
		next_pwm_period_counter = 0;
	end
	if(~(|pwm_period_counter)) begin
		next_pwm_ch = 2'b00;
	end
	if(pwm_period_counter == pwm_duty_cycle_0) begin
		next_pwm_ch[0] = 1;
	end
	if(pwm_period_counter == pwm_duty_cycle_1) begin
		next_pwm_ch[1] = 1;
	end

	/*
	pwm ctrl:
		cmd[24]: 0: for ch0, 1: for ch1
		cmd[19:0]
	*/
	if(LS_Set_PWM) begin
		if(cmd_param[24]) begin
			next_pwm_duty_cycle_1 = cmd_param[19:0];
		end else begin
			next_pwm_duty_cycle_0 = cmd_param[19:0];
		end
	end
	
	/*pump ctrl*/
	next_pump_ctrl = pump_ctrl;
	if(LS_Set_Pump) begin
		next_pump_ctrl = cmd_param[0];
	end
	
	/* Read status */
	next_FIFO_DIN  = FIFO_DIN;
	next_FIFO_WR_EN = 0;
	if(LS_RD_Status & (!FIFO_FULL)) begin
		next_FIFO_DIN = work_status;
		next_FIFO_WR_EN = 1;
	end
end

A3967SLB A3967SLB_inst_0 (
    .CLK(CLK_Core), 
    .nRST(nRST), 

    .Step_Num(cmd_param[12:0]), 
    .direction(cmd_param[24]), 
    .launch(launch_step_0), 
    .step_ctrl(step_ctrl), 
	
	.edge_far(edge_x_left),
	.edge_near(edge_x_right),
	
    .EN(EN_0), 
    .DIR(DIR_0), 
    .STEP(STEP_0)
    );

A3967SLB A3967SLB_inst_1 (
    .CLK(CLK_Core), 
    .nRST(nRST), 

    .Step_Num(cmd_param[12:0]), 
    .direction(cmd_param[24]), 
    .launch(launch_step_1), 
    .step_ctrl(step_ctrl), 
	
	.edge_far(edge_y_front),
	.edge_near(edge_y_back),

    .EN(EN_1), 
    .DIR(DIR_1), 
    .STEP(STEP_1)
    );
endmodule
